/**@module documentParse*/

var rmsAttr = /jc-(\w+)-?(.*)/;
var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase())

//var ons = oneObject("animationend,blur,change,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scroll");
var openTag, closeTag, rexpr, rexprg, rbind, needWatchTag = '#';


var rfilters = /\|\s*(\w+)\s*(\([^)]*\))?/g,
    r11a = /\|\|/g,
    r11b = /U2hvcnRDaXJjdWl0/g;

/**
 * attribute扫描先后顺序
 *
 * @readOnly
 * @type {Object}
 */
var attrPriority = {
    "reuse": 120,
    "if": 100,
    "repeat": 80,
    "dupfilter": 60,
    "data": 90
};


var dParseErr = minErr("document parse");

/**
 * 更换表达式包裹符,注意，数组两个值不能相等
 *
 * @alias jc.config
 * @name  interpolate
 * @example
 * interpolate(['_#','#_'])
 *
 * @param  {array} array  notice:array[0]!==array[1]
 */
config.interpolate = function(array) {
    if (Array.isArray(array) && array[0] && array[1] && array[0] !== array[1]) {

        openTag = array[0]
        closeTag = array[1]
        var o = openTag,
            c = closeTag;

        rexpr = new RegExp(o + "(.*?)" + c)
        rexprg = new RegExp(o + "(.*?)" + c, "g")
        rbind = new RegExp(o + ".*?" + c + "|\\sjc-")
    }
}
config.interpolate(['{{', "}}"])


/**
 * 扫描dom元素的attributes
 * @namespace documentParse
 * @param  {Element} elem
 * @param  {object} data
 * @param  {tempHelper.tempHelper} th
 */
function scanAttr(elem, data, th) {
    var match, attributes = elem.attributes,
        bindings = [];

    for (var i = 0, attr; attr = attributes[i++];) {
        if (match = attr.name.match(rmsAttr)) {
            var type = match[1]
            var param = match[2] || ""
            var binding = {
                type: type,
                param: param,
                element: elem,
                name: match[0],
                value: attr.value,
                priority: attrPriority[type] || 0
            }
            if (param === 'loop' && type === 'if') {
                binding.priority -= 30
            }
            bindings.push(binding)
            //}
        }
    }

    if (bindings[0]) {

        bindings = bindings.sort(function(v1, v2) {
            return v2.priority - v1.priority
        })
        var firstBind = bindings[0]
        scanDispatch(bindings, data, th) //bindings会被修改

        if (firstBind.type === 'reuse' && firstBind.param === 'hide') {
            return;
        }
    }
    if (elem.parentNode && !stopScan[elem.tagName] && rbind.test(elem.innerHTML /*.replace(rlt, "<").replace(rgt, ">")*/ )) {
        scanNodes(elem, data, th) //扫描子孙元素
    }
}

/**
 * 扫描element子结点
 * @namespace documentParse
 * @param  {Element} parent
 * @param  {object} data
 * @param  {tempHelper.tempHelper} th
 */
function scanNodes(parent, data, th) {
    var node = parent.firstChild
    while (node) {
        var nextNode = node.nextSibling
        if (node.nodeType === 1) {
            // scanTag(node, data)
            scanAttr(node, data, th)
        } else if (node.nodeType === 3) {
            if (rexpr.test(node.data)) {
                scanText(node, node.data, data, th)
            }
        } else if (node.nodeType === 8) {
            // if (rexpr.test(node.innerHTML)) { 
            //     scanText(node, node.innerHTML, data, th)
            // }
        }
        node = nextNode
    }
}


/**
 * 扫描文本节点
 * @namespace documentParse
 * @param  {textNode} textNode
 * @param  {String} text
 * @param  {object} data
 * @param  {tempHelper.tempHelper} th
 */
function scanText(textNode, text, data, th) {
    var bindings = [],
        tokens = scanExpr(text)
    if (tokens.length) {
        for (var i = 0, token; token = tokens[i++];) {
            var node = document.createTextNode(token.value) //将文本转换为文本节点，并替换原来的文本节点
            if (token.expr) {
                var binding = {
                    type: "text",
                    node: node,
                    nodeType: 3,
                    value: token.value,
                    needWatch: token.needWatch,
                    filters: token.filters
                }

                bindings.push(binding) //收集带有插值表达式的文本
            }
            documentFragment.appendChild(node)
        }
        textNode.parentNode.replaceChild(documentFragment, textNode)
        scanDispatch(bindings, data, th)
    }
}

/**
 * @typedef {Object} Filter
 * @property {String} method  jc.filters的方法名称
 * @property {Array.<String>} args 运行jc.filters[method]的参数
 *
 */

/**
 * @typedef {Array.<Object>} textExpr
 * @property {boolean} expr 是否是表达式
 * @property {String} value 表达式的值
 * @property {boolean=} needWatch 需不需要做监控处理
 * @property {Array.<Filter>=} filters 过滤器集合
 *
 */

/**
 * 处理表达式值，过滤出filters和需要绑定的属性
 * @namespace documentParse
 * @param  {String} str
 * @return {Object}
 */
function scanExpr(str) {
    var tokens = [],
        value, start = 0,
        stop
    do {
        stop = str.indexOf(openTag, start)
        if (stop === -1) {
            break;
        }
        value = str.slice(start, stop)
        if (value) { // {{ 左边的文本
            tokens.push({
                value: value,
                expr: false
            })
        }
        start = stop + openTag.length
        stop = str.indexOf(closeTag, start)
        if (stop === -1) {
            break;
        }
        value = str.slice(start, stop)
        if (value) { //处理{{ }}插值表达式
            var needWatch = false
            if (!value.indexOf(needWatchTag)) { //过滤需要监控的标签
                value = value.replace(needWatchTag, "")
                needWatch = true
            }
            var leach = []
            if (~value.indexOf("|")) { // 抽取过滤器 先替换掉所有短路与
                value = value.replace(r11a, "U2hvcnRDaXJjdWl0") //btoa("ShortCircuit")
                value = value.replace(rfilters, function(c, d, e) {
                    var args = [];
                    if (e) {
                        e.slice(1, -1).replace(rword, function(v) {
                            args.push(v.trim());
                        })
                    }
                    leach.push({
                        method: d,
                        args: args
                    })
                    return ""
                })
                value = value.replace(r11b, "||") //还原短路与
            }
            tokens.push({
                value: value,
                expr: true,
                needWatch: needWatch,
                filters: leach.length ? leach : void 0
            })
        }
        start = stop + closeTag.length
    } while (1)
    value = str.slice(start)
    if (value) { //}} 右边的文本
        tokens.push({
            value: value,
            expr: false
        })
    }

    return tokens
}


// function getCurrentTmp() {
//     return getCurrentTmp.tmp
// }

/**
 * 渲染页面的核心方法
 * 根据url去抓模板，然后将数据渲染进模板，并初始化模板运行状态，
 * 注意: $div都是独一无二的，如果同一个$div进行二次渲染的话，
 * 模板运行状态会被重置，其他模板 关于此模板的数据订阅也会被重置
 * 需要重新订阅
 *
 * @memberOf documentParse
 * @param  {object}   data
 * @param  {string=}   url     url
 * @param  {Node}     $div     the jquery node to render in
 * @param  {funciton=} callback
 * @param {object=} options  配置，暂时没有用处
 */
function render(data, url, $div, callback, options) {
    if (typeof arguments[1] !== 'string') {
        callback = $div
        $div = url
    }
    var ct = getType(callback)

    if (ct === 'object')
        options = ct
    if (ct !== 'function')
        callback = noop
    var th = tempHelper($div);
    getBufferedView(url, function(content) {
        scan(content)
        callback(th)
    });

    function scan(text) {
        var elem = $div[0];
        if (text) {
            th.empty();
            th.html(text);
            th._data("data", data)
            th._data("id", $nextUid())
            th._data("url", url)
            scanNodes($div[0], data, th);
        }
        //elem.style.visibility = ""
    }
}

// function renderWithoutUrl